/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package fr.ove.openmath.jome.formaters.om;

/**
 *
 * @author Mr.Sam
 */
import java.util.*;
import fr.ove.utils.*;
import fr.ove.openmath.jome.model.*;
import fr.ove.openmath.jome.formaters.om.*;

/**
* Formats the formula tree structure as its corresponding OpenMath object.<BR>
* This is the formater for integrals.
*
* @author © 2000 DIRAT Laurent
* @version 1.0 21/02/2000
*/
public class DifferentiationFormater implements Formater {
    /**
    * Returns the specified object formatted as a string.
    * @param formatedObject the formatted object (for structured object, could represents the beginning).
    * @param formaterRepository where the different other formaters are.
    * @param obj the object to format.
    */
    public String format(String formatedObject, FormaterRepository formaterRepository, Object obj) {
        OpenMathFormater omFormater = (OpenMathFormater) formaterRepository;
        Differentiation fts = (Differentiation) obj;
        
        Formater formater;
        FormulaTreeStructure child;
        
        String objectId = fts.getResourceIdentifier();
        
        String cdName = omFormater.getCdName(objectId);
        
        if (fts.isPartial()) {
            formatedObject += omFormater.writeStartApplication();
            formatedObject += omFormater.writeSymbol(cdName, "partialdiff");
            
            // Création de la liste des indexes des variables
            Vector variableList = new Vector();
            Vector variableNameList = new Vector();
            FormulaTreeStructure derivated = (FormulaTreeStructure) fts.getChild(1);
            createVariableList(derivated, variableList, variableNameList);
            
            formatedObject += omFormater.writeStartApplication();
            formatedObject += omFormater.writeSymbol("list1", "list");
            
            int count = fts.getNbChildren();
            int index;
            for (int i = 2; i < count; i++) {
                index = findIndex(((Variable)((FormulaTreeStructure) fts.getChild(i)).getChild(0)).getValue(), variableNameList);
                if (index != -1)
                    formatedObject += omFormater.writeInteger(""+index);
            }
            formatedObject += omFormater.writeEndApplication();
            
            // Création du bind
            formatedObject += omFormater.writeStartBinding();
            formatedObject += omFormater.writeSymbol("lambda");
            
            // On met les variables liées.
            formatedObject += omFormater.writeStartBoundVariables();
            child = (FormulaTreeStructure) variableList.elementAt(0);
            objectId = child.getResourceIdentifier();
            formater = formaterRepository.getFormater(objectId);
            formatedObject = formater.format(formatedObject, formaterRepository, child);
            count = variableList.size();
            for (int i = 1; i < count; i++) {
                child = (FormulaTreeStructure) variableList.elementAt(i);
                formatedObject = formater.format(formatedObject, formaterRepository, child);
            }
            formatedObject += omFormater.writeEndBoundVariables();
            
            // On met maintenant l'objet du bind, i.e. l'argument.
            child = (FormulaTreeStructure) fts.getChild(1);
            objectId = child.getResourceIdentifier();
            formater = formaterRepository.getFormater(objectId);
            formatedObject = formater.format(formatedObject, formaterRepository, child);
            
            formatedObject += omFormater.writeEndBinding();
            formatedObject += omFormater.writeEndApplication();
        }
        else {
            int order = fts.getOrder();
            for (int i = 0; i < order; i++) {
                formatedObject += omFormater.writeStartApplication();
                // On récupère le nom du CD, puisque le symbole est déterminé ici.
                formatedObject += omFormater.writeSymbol(cdName, "diff");
            
                // Création du bind
                formatedObject += omFormater.writeStartBinding();
                formatedObject += omFormater.writeSymbol("fns1", "lambda");
                
                // On met la variable liée.
                formatedObject += omFormater.writeStartBoundVariables();
                child = (FormulaTreeStructure) fts.getChild(2);
                // Si l'ordre de la dérivée est > 1, alors child est un slot contenant un Superscript.
                // Il faut aller chercher la variable
                if (order > 1)
                    child = (FormulaTreeStructure) ((FormulaTreeStructure) child.getChild(0)).getChild(0);
                    
                objectId = child.getResourceIdentifier();
                formater = formaterRepository.getFormater(objectId);
                formatedObject = formater.format(formatedObject, formaterRepository, child);
                formatedObject += omFormater.writeEndBoundVariables();
            }
            
            // On met maintenant l'objet du bind, i.e. l'argument.
            child = (FormulaTreeStructure) fts.getChild(1);
            objectId = child.getResourceIdentifier();
            formater = formaterRepository.getFormater(objectId);
            formatedObject = formater.format(formatedObject, formaterRepository, child);
                
            for (int i = 0; i < order; i++) {
                formatedObject += omFormater.writeEndBinding();
                formatedObject += omFormater.writeEndApplication();
            }
        }
        
        return formatedObject;
    }
    
    private void createVariableList(FormulaTreeStructure fts, Vector variableList, Vector variableNameList) {
        if (fts.getResourceIdentifier().equals("VARIABLE")) {
            if (!fts.isTemplate()) {
                String value = ((Variable) fts).getValue();
                boolean addValue = true;
                String stored;
                
                for (Enumeration e = variableNameList.elements(); e.hasMoreElements(); ) {
                    stored = (String) e.nextElement();
                    if (value.equals(stored)) {
                        addValue = false;
                        break;
                    }
                }
                    
                if (addValue) {
                    variableNameList.addElement(value);
                    variableList.addElement(fts);
                }
            }
        }
        else {
            int count = fts.getNbChildren();
            for (int i = 0; i < count; i++)
                createVariableList((FormulaTreeStructure) fts.getChild(i), variableList, variableNameList);
        }
    }
    
    private int findIndex(String varName, Vector variableNameList) {
        int index = -1;
        String stored;
        
        int count = variableNameList.size();
        for (int i = 0; i < count; i++ ) {
            stored = (String) variableNameList.elementAt(i);
            if (varName.equals(stored)) {
                index = i + 1;
                break;
            }
        }
        
        return index;
    }
}